﻿using System.Collections.Generic;
using System.IO;

namespace SuperKit
{

    public class FileNameGroupItem {
        public string Name { get; }
        public List<FileInfo> Files { get; }
        public string TrimName { get; }
        public int Count => Files.Count;

        public FileNameGroupItem(string groupName) {
            Name = groupName;            
            Files = new List<FileInfo>();

            // TrimName用于建立新的文件名
            TrimName = Name.Trim(FileNameGroup.SPLIT.ToCharArray());
            if (TrimName.Length == 0) {
                TrimName = Name;
            }

        }

        public void Add(FileInfo fileInfo) {
            Files.Add(fileInfo);
        }

        public string CutHeander(FileInfo file) {
            return file.Name.Replace(Name, "");
        }
    }

    /// <summary>
    /// 目前这个在处理数字的时候还有瑕疵，暂时先这样吧。
    /// </summary>
    public class FileNameGroup {
        public const int LOWER_DIFF = 'a' - 'A';
        public const int UPPER_START = 'A';
        public const int UPPER_END = 'Z';
        public const int LOWER_START = 'a';
        public const int LOWER_END = 'z';
        public const int NUMBER_START = '0';
        public const int NUMBER_END = '9';
        public const string SPLIT = " _.-(";
        public const string NUMBER = "0123456789";

        public DivideCatalog Parent { get; }
        public FileGroup Group { get; }
        public List<FileNameGroupItem> Items { get; }
        public string[] FileNames { get; }
        public bool[] Cataloged { get; }

        public FileNameGroup(DivideCatalog parent, FileGroup group) {
            Parent = parent;
            this.Group = group;
            Items = new List<FileNameGroupItem>();
            FileNames = new string[Group.Files.Length];
            Cataloged = new bool[Group.Files.Length];
            for (int i = 0; i < Group.Files.Length; i++) {
                FileNames[i] = Path.GetFileNameWithoutExtension(Group.Files[i].Name);
                Cataloged[i] = false;
            }
        }

        public void Analysis() {
            for (int i = 0; i < FileNames.Length; i++) {
                if (Cataloged[i]) { continue; }
                Process(Group.Files[i]);
            }
        }

        private void Process(FileInfo file) {
            string name = Path.GetFileNameWithoutExtension(file.Name);

            // 跳过只有数字的项目
            if (IsPureNumber(name)) {
                return;
            }
                        
            int index = GetNextSplitIndex(name, 0);
            // 如果此项没有合法的分隔符，则跳出
            if (index == -1) {
                return;
            }

            int lastCount = 0;
            int pointer = index;
            int lastPointer = pointer;
            var currentName = name.Substring(0, pointer);


            while (pointer < name.Length) {
                // 检查此索引之前
                var count = GetEqualCount(name, pointer);

                // 当最后一个项目的相等数小于当前项目，表示当前已经是最大了。跳出
                if (count < lastCount) {
                    break;                    
                } else {
                    lastCount = count;
                    lastPointer = pointer;
                }

                // 当以数字为索引的时候，表示已经是最后一次分隔符，不继续向前检查
                if (char.IsNumber(name[pointer])){
                    break;
                }

                var nextIndex = GetNextSplitIndex(name, pointer + 1);
                if (nextIndex == -1) {                    
                    break;
                }

                pointer = nextIndex;
            }

            // 当执行到此处，而且拥有合法的Count的时候，进行处理
            // 当项目只有他一个的时候，不做任何处理
            if (lastCount == 0) {
                return;
            }

            // 这里的pointer需要减1，因为这个位置的索引是包括了下一个Split的。
            currentName = name.Substring(0, lastPointer);
            var groupName = currentName;// currentName.Trim(SPLIT.ToCharArray());
            // 这是一个防错机制，因为有时候对方以“_”开头，结果只有“_”。
            if (groupName.Length == 0) {
                groupName = currentName;
            }
            AddGroup(groupName);

            //Parent.Flush("{0}, pointer:{1}, count:{2}", name, pointer, lastCount);
        }

        private void AddGroup(string groupName) {
            // 检查是否拥有此Group
            var g = GetGroup(groupName);
            // 如果拥有Group，则不做处理
            if (g != null) {
                return ;
            }

            FileNameGroupItem item = new FileNameGroupItem(groupName);
            Items.Add(item);
            Pick(item);
        }

        private void Pick(FileNameGroupItem item) {
            for (int i = 0; i < FileNames.Length; i++) {
                if (Cataloged[i]) { continue; }

                if (IsEqual(FileNames[i], item.Name, item.Name.Length)) {
                    item.Add(Group.Files[i]);
                    Cataloged[i] = true;
                }
            }

        }

        private FileNameGroupItem GetGroup(string groupName) {
            foreach (var i in Items) {
                if (Kit.IsEqual(i.Name, groupName)) {
                    return i;
                }
            }
            return null;
        }


        public int GetEqualCount(string name, int charCount) {
            int count = 0;
            for (int i = 0; i < FileNames.Length; i++) {
                if (Cataloged[i]) { continue; }

                var n = FileNames[i];
                // 跳过他自己
                if (Kit.IsEqual(n, name)) {
                    continue;
                }

                if (IsEqual(name, n, charCount)) {
                    count++;
                }
            }
            return count;
        }

        /// <summary>
        /// 获取第一个分格符号的
        /// </summary>
        public static int GetStartIndex(string a, string chars, int start = 0) {
            for (int i = start; i < a.Length; i++) {
                for (int c = 0; c < chars.Length; c++) {
                    if (a[i] == chars[c]) {
                        return i;
                    }
                }
            }
            return -1;
        }

        public static bool IsPureNumber(string a) {
            for (int i = 0; i < a.Length; i++) {
                bool isNumber = false;
                for (int c = 0; c < NUMBER.Length; c++) {
                    if (a[i] == NUMBER[c]) {
                        isNumber = true;
                        break;
                    }
                }
                if (!isNumber) {
                    return false;
                }
            }
            return true;
        }

        /// <summary>
        /// 检查在Index之前，此字符串是否相等
        /// </summary>
        public static bool IsEqual(string a, string b, int count) {            
            for (int i = 0; i < count; i++) {
                if (i >= a.Length || i >= b.Length) {
                    return false;
                }

                char ac = a[i];
                char bc = b[i];

                // 对大小写进行转化
                if (ac >= UPPER_START && ac <= UPPER_END) {
                    ac = (char)(ac + LOWER_DIFF);
                }
                if (bc >= UPPER_START && bc <= UPPER_END) {
                    bc = (char)(bc + LOWER_DIFF);
                }

                if (ac != bc) {
                    return false;
                }

            }

            return true;
        }


        public static int GetNextSplitIndex(string name, int start) {
            // 获取起始位置，必须是一个分隔符，合法的分隔符有空格，下划线等。
            int index = GetStartIndex(name, SPLIT, start);
            // 如果没有获得一个合法的分隔符，表示这个文件名是直接用名称加数字，
            // 这里选择用数字做为分隔符（即选择第一个数值之前的名称）
            return index == -1 ? GetStartIndex(name, NUMBER, start) : index;
        }

        public static string GetStartSplitName(string name, int start = 0) {
            int index = GetNextSplitIndex(name, 0);
            if (index == -1) {
                return name;
            } else {
                return name.Substring(0, index);
            }
        }
    }
}
